
#ifndef _PARAM_HANDLER_HPP_
#define _PARAM_HANDLER_HPP_

#include <iostream>
#include <fstream>
#include <string>
#include <vector>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>

using std::string;
using std::vector;

class param_handler {
	vector<string> spar;
	string prefix;
	bool error;
	string errormsg;

public:
	// prefix: this is simply the parameter prefix like "-" or "--"
	// or anything

	param_handler() {
		error=false;
		errormsg.assign("");
		prefix.assign("");
	}
	
	void reset_error(){error=false;errormsg.assign("");}

	void set_error(string msg){
		error=true,
		errormsg="param_handler: ";
		errormsg.append(msg);
	}
	
	bool is_error(){return error;}
	string error_message(){if(error)return errormsg; return "";}

	param_handler(int argc, char* argv[]) {
		prefix.assign("");
		for(int i=0;i<argc;i++) {
			spar.push_back(argv[i]);
		}
	}
	
	int  size(){return spar.size();}
	void push_val(string p){spar.push_back(p);}
	void push_par(string p){spar.push_back(prefix+p);}
	void push_pair(string p, string v){push_par(p);push_val(v);}

	void clear(){spar.clear();}
	void set_prefix(const char* pp){prefix.assign(pp);}

	string operator[](int idx){
		string retstr("");
		if(idx<spar.size()) retstr.assign(spar[idx]);
		return retstr;
	}
	
	void shift(){
		if(spar.empty()) return;
		spar.erase(spar.begin());
	}
	
	void shift(int n){
		if(n>spar.size())n=spar.size();
		for(int i=0;i<n;i++)shift();
	}
	
	bool exist(string p){
		for(int i=0;i<spar.size();i++) {
			if(spar[i]==(prefix+p)) return true;
		}
		return false;
	}
	
	// returns negative if the parameter does not exist
	int index_of(string p){
		for(int i=0;i<spar.size();i++) {
			if(spar[i]==(prefix+p))return i;
		}
		return -1;
	}
	
	vector<string>::iterator iter_of(string p){
		vector<string>::iterator pv;
		for(pv=spar.begin();pv!=spar.end();pv++)
			if(*pv==p) return pv;
		return spar.end();
	}

	void remove(string p) {
		vector<string>::iterator idx=iter_of(p);
		if(idx==spar.end()) return;
		spar.erase(idx);
	}

	void remove_pair(string p) {
		vector<string>::iterator idx=iter_of(p);
		if(idx==spar.end()) return;
		spar.erase(idx);
		if(idx!=spar.end())spar.erase(idx);
	}

	//-------------------------------------------------------------
	// FIXME! untested....

	double as_double(int idx) {
		double retd=0.0;
		reset_error();
		if(idx<spar.size()){
			char st[256],*pt;
			spar[idx].copy(st,256);
			retd=strtod(st,&pt);
			if(pt==st) {
				retd=0; // to make sure
				set_error("conversion to double failed");
			}
		} else set_error("out of range");
		return retd;			
	}
	
	int as_int(int idx){
		int reti=0;
		reset_error();
		if(idx<spar.size()){
			char st[256],*pt;
			spar[idx+1].copy(st,256);
			reti=strtol(st,&pt,10);
			if(pt==st) {
				reti=0;
				set_error("conversion to integer failed");
			}
		} else set_error("out of range");
		return reti;
	}
	
	string as_string(int idx){
		reset_error();
		if(idx>=spar.size()) {
			set_error("out of range");
			return "";
		}
		return spar[idx];
	}

    //--------------------------------------------------------------

	string string_value(string p){
		if(!exist(p)) return "";
		int idx=index_of(p);
		
		string rets("");
		if((idx+1)<spar.size()) rets=spar[idx+1];
		return rets;
	}
	    
	// just return zero if not exist
	double double_value(string p){
		if(!exist(p)) return 0.0;
		int idx=index_of(p);
		
		if(idx<spar.size()-1){
			char st[256],*pt;
			spar[idx+1].copy(st,256);
			double retd=strtod(st,&pt);
			if(pt==st) {
				throw (string("invalid double value for parameter ")+spar[idx]).c_str();
			}
			return retd;
		}
		throw (string("double value required for parameter ")+spar[idx]).c_str();
	}
	
	int int_value(string p){
		if(!exist(p)) return 0;
		int idx=index_of(p);
		
		if(idx<spar.size()-1){
			char st[256],*pt;
			spar[idx+1].copy(st,256);
			int reti=strtol(st,&pt,10);
			if(pt==st) {
				throw (string("invalid integer value for parameter ")+spar[idx]).c_str();
			}
			return reti;
		}
		throw (string("integer value requiered for parameter ")+spar[idx]).c_str();
	}

	void peek(string p, string& var){if(exist(p)) var=string_value(p);}
	void peek(string p, double &var){if(exist(p)) var=double_value(p);}
	void peek(string p, int &var){if(exist(p)) var=int_value(p);}
	void peek(string p, bool &var){if(exist(p)) var=true;}

//----------------------------
	
	void dump(){
		for(int i=0;i<spar.size();i++)
			std::cout << spar[i] << " ";
		std::cout << "\n";
	}
	
};

#endif
